/*
 * baza.cpp
 * 
 * Copyright 2013 Kamil Cukrowski <kamil@dyzio.pl>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation version 2.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 * 
 */
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <errno.h>
#include <string.h>
#include <sstream>
#include <mysql/mysql.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
using namespace std;
#include "baza.h"

#define PDEBUG(fmt, ...)  printf("baza "fmt, ##__VA_ARGS__)
//#define PDEBUG(fmt, ...) /* placeholder :D */


static char server[] = "localhost";
static char user[] = "serwus";
static char password[] = "serwus123";
static char database[] = "qsearch";
static char table[] = "qsearch6";
static char hosts_table[] = "hosts3";


std::string LongToString(long long value)
{
	char buff[256];
	snprintf(buff, 256, "%lld", value);
	return (string)buff;
}

void replace(std::string& str, const std::string& from, const std::string& to) {
	if(from.empty())
		return;
	size_t start_pos = 0;
	while((start_pos = str.find(from, start_pos)) != std::string::npos) {
		str.replace(start_pos, from.length(), to);
		start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
	}
}

class BazaPlik:public IBaza {
 protected:
 
	string nazwa_pliku;
	bool otwarty;
	string hostname;
	string tmptable;
	unsigned ilosc_wpisow;
	ostream &plik;
	MYSQL *conn;
	
 public:	
	BazaPlik(const string &hostname, ostream &plik_log):plik(plik_log), hostname(hostname) 
	{
		otwarty = false;
		ilosc_wpisow = 0;
		string query;
		ostringstream ss;
		
		tmptable=hostname;
		
		ss.clear();
		ss << (int)'-';
		replace(tmptable, "-", ss.str());
		
		ss.clear();
		ss << (int)'.';
		replace(tmptable, ".", ss.str());
				
		conn = mysql_init(NULL);
AGAIN:
		if ( !mysql_real_connect(conn, server, user, password, database, 0, NULL, 0) ) {
			fprintf(stderr, "%s msyql errno: %d, error: %s \n",  hostname.c_str(), mysql_errno(conn), mysql_error(conn));
			plik << "msyql errno: "<< mysql_errno(conn)<<" error: "<< mysql_error(conn) << endl;
			if ( mysql_errno(conn) == 1040 ) { // too many connections error
				plik << "reconnecting to mysql" << endl;
				fprintf(stderr, "%s reconnecting to mysql\n", hostname.c_str());
				sleep(1);
				goto AGAIN;
			}
			return;
		}
		PDEBUG("CONNECTED \n");
		
		query = "create table " + tmptable + " like " + table + ";";
		PDEBUG(" QUERY: %s \n", query.c_str());
		if (mysql_query(conn, query.c_str())) {
			fprintf(stderr, "ERROR 000000000000 \n query:%s mysql_error:%s\n", query.c_str(), mysql_error(conn));
			return;
		}
		
		query = "truncate table " + tmptable + "; ";
		PDEBUG(" QUERY: %s \n", query.c_str());
		if (mysql_query(conn, query.c_str())) {
			fprintf(stderr, "ERROR -------- \n query:%s mysql_error:%s\n", query.c_str(), mysql_error(conn));
			return;
		}
		
		otwarty = true;
	} 
	~BazaPlik() {
		if (!otwarty)
			return;
		string query;
					
		query =	(string)"drop table " + tmptable + "; ";
		PDEBUG(" QUERY: %s \n", query.c_str());
		if (mysql_query(conn, query.c_str())) {
			fprintf(stderr, "ERROR: 33333333 \n query:%s mysql_error:%s\n", query.c_str(), mysql_error(conn));
		}
		
		mysql_close(conn);
	}

	void DodajWpis(unsigned poziom_katalogu, const string &protocol, const string &hostname, const string &path, const string& file, unsigned long long rozmiar) 
	{
		if ( !otwarty )
			return;
		
		ilosc_wpisow++;
	
		/* replace ' with \', cause we send strings in ' signs */
		string _path = path;
		string _file = file;
		replace(_path, "'", "\\'");
		replace(_file, "'", "\\'");
		
		string query = (string)"insert into " + tmptable + " values ('" 
			+ protocol + (string)"','" 
			+ hostname + (string)"','" 
			+ _path  + (string)"','" 
			+ _file + (string)"',"
			+ LongToString(rozmiar) + (string)");";
		PDEBUG(" QUERY: %s \n", query.c_str());
		
		plik << query << endl;
		
		/* send SQL query */
		if (mysql_query(conn, query.c_str())) {
			fprintf(stderr, "mysql_query error: %s\n", 	mysql_error(conn));
			return;
		}
	}
	
	void flush()
	{
		if ( !otwarty )
			return;
		if ( ilosc_wpisow == 0 ) {
			PDEBUG("brak wpisów - nie ma co flushować\n");
			return;
		}
		string query;
		
		query = (string)"update " + hosts_table + " set scanned=NOW() where hostname = '"+hostname+"'; ";
		PDEBUG(" QUERY: %s \n", query.c_str());
		if (mysql_query(conn, query.c_str())) {
			fprintf(stderr, "ERROR: 100001111 \n query:%s mysql_error:%s\n", query.c_str(), mysql_error(conn));
		}
		
		query = (string)"delete from " + table + " where hostname = '" + hostname + "'; ";
		PDEBUG(" QUERY: %s \n", query.c_str());
		if (mysql_query(conn, query.c_str())) {
			fprintf(stderr, "ERROR: 111111111 \n query:%s mysql_error:%s\n", query.c_str(), mysql_error(conn));
		}
		
		query =	(string)"insert into " + table + " select * from " + tmptable + "; ";
		PDEBUG(" QUERY: %s \n", query.c_str());
		if (mysql_query(conn, query.c_str())) {
			fprintf(stderr, "ERROR: 2222222222 \n query:%s mysql_error:%s\n", query.c_str(), mysql_error(conn));
		}
	}
};

IBaza *OtworzBazePlik(const string &hostname, ostream &plik_log)
{
	return new BazaPlik(hostname, plik_log);
}
